<?php

namespace app\components;

/**
 *
 */
abstract class Controller
{
    protected $defaultAction = 'index';

    /**
     * 分发整个控制器的 action
     * e.g
     * Macaw::any('test/([\w-]+)', \app\controllers\TestController::class . '@distribute');
     *  can match: `/test/predis /test/redis /test/...`, but not match `/test`
     * If want to match all '/test', can use:
     *  Macaw::any('test(/[\w-]+)?', \app\controllers\TestController::class . '@distribute');
     *
     * Macaw::any('test/(\w+)/(:num)', \app\controllers\TestController::class . '@distribute');
     *  can match: test/predis/12 test/redis/34 test/.../345
     *
     * @param $action
     * @throws \HttpException
     */
    public function distribute($action = '')
    {
        $action = $action?: $this->defaultAction;

        if ( $params = func_get_args() ) {
            array_shift($params);// the first argument is `$action`
        }

        $action = trim($action, '/');

        // convert 'first-second' to 'firstSecond'
        if ( strpos($action, '-') ) {
            $action = ucwords(str_replace('-', ' ', $action));
            $action = str_replace(' ','',lcfirst($action));
        }

        // the action method exists and only allow access public method.
        if ( method_exists($this, $action) && (
            ($refMethod = new \ReflectionMethod($this, $action)) && $refMethod->isPublic()
        )) {
            $this->beforeAction($action);

            $params ? call_user_func_array([$this, $action], $params) : $this->$action();

            $this->afterAction($action);
        } elseif ( method_exists($this, 'pageNotFound')) {
            $this->pageNotFound();

            // call 'onNotFound' service.
        } elseif ( $notFoundHandler = BaseApp::get(BaseApp::EVT_NOT_FOUND, false) ) {
            $notFoundHandler();
        } else {
            throw new \HttpException('Sorry, the page you want to visit already does not exist!');
        }
    }

//    public function __invoke()
//    {
//        de(func_get_args());
//    }

    protected function beforeAction($action)
    {
        # code...
    }

    protected function afterAction($action)
    {
        # code...
    }

    protected function render($view, array $data = [])
    {
        /** @var Output $resp */
        $resp = \App::view()->render($view, $data);
        $resp->send();
    }

    protected function renderBody($content, array $data = [])
    {
        /** @var Output $resp */
        $resp = \App::view()->renderBody($content, $data);

        $resp->send();
    }
}
